package work.jame.blog.service.impl;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.CircleCaptcha;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.http.useragent.UserAgent;
import cn.hutool.jwt.JWTUtil;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import work.jame.blog.configuration.security.LoginUser;
import work.jame.blog.configuration.security.SecurityConfig;
import work.jame.blog.framework.constant.UserConfigurationConstant;
import work.jame.blog.framework.exception.certificate.VerificationCodeException;
import work.jame.blog.framework.exception.db.DataNotExistException;
import work.jame.blog.framework.exception.db.InsertDataBaseException;
import work.jame.blog.framework.exception.db.UpdateDataBaseException;
import work.jame.blog.framework.exception.user.NewIpLoginException;
import work.jame.blog.framework.exception.user.UserAuthenticationException;
import work.jame.blog.framework.exception.user.UserExistException;
import work.jame.blog.framework.result.PageResult;
import work.jame.blog.framework.utils.EmailUtils;
import work.jame.blog.framework.utils.SqlUtils;
import work.jame.blog.framework.utils.ThreadPoolUtil;
import work.jame.blog.framework.utils.UserUtils;
import work.jame.blog.framework.utils.http.IpUtils;
import work.jame.blog.framework.utils.http.WebUtils;
import work.jame.blog.framework.utils.redis.RedisService;
import work.jame.blog.framework.utils.redis.RedisUtils;
import work.jame.blog.framework.utils.security.SpringSecurityUtils;
import work.jame.blog.pojo.*;
import work.jame.blog.mapper.UserMapper;
import work.jame.blog.pojo.dto.UserDTO;
import work.jame.blog.pojo.vo.PublishUserVO;
import work.jame.blog.pojo.vo.UserVO;
import work.jame.blog.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author Jame
 * @since 2023-05-09
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Resource
    private UserMapper userMapper;

    @Autowired
    private AuthenticationManager authenticationManager;


    @Autowired
    private UserLoginLogService userLoginLogService;

    @Autowired
    private UserConfigurationService userConfigurationService;

    @Autowired
    private UserRiceGrainsLogService userRiceGrainsLogService;

    @Autowired
    private UserCollectGroupService userCollectGroupService;


    @Autowired
    private RedisService redisService;

    @Override
    @Transactional
    public String login(UserDTO userDTO) {
        User user = userDTO.getUser();
        String email = user.getEmail();
        String userLoginFailEmailKey = RedisUtils.getUserLoginFailEmailKey(email);
        //如果之前失败过,获取失败次数,如果大于3则检查验证码是否正确
        if (redisService.hasKey(userLoginFailEmailKey)) {
            Integer emailFailNumber = redisService.getCacheObject(userLoginFailEmailKey);
            if (!Objects.isNull(emailFailNumber) && emailFailNumber > 3) {
                String userLoginCodeKey = RedisUtils.getUserLoginCodeKey(email);
                String redisLoginCode = redisService.getCacheObject(userLoginCodeKey);
                if (Objects.isNull(redisLoginCode) || !redisLoginCode.equals(userDTO.getCode())) {
                    throw new UserAuthenticationException("验证码不正确", emailFailNumber);
                }
            }
        }
        UsernamePasswordAuthenticationToken authenticationToken =
                new UsernamePasswordAuthenticationToken(user.getEmail(), user.getPassword());
        Authentication authenticate = null;
        try {
            authenticate = authenticationManager.authenticate(authenticationToken);
        } catch (AuthenticationException e) {
            //登录认证失败处理
            loginAuthenticationFailHandler(userDTO);
        }
        if (Objects.isNull(authenticate)) {
            throw new UserAuthenticationException("用户名或密码错误");
        }
        //登录成功则生成token
        LoginUser loginUser = (LoginUser) authenticate.getPrincipal();
        User dbUser = loginUser.getUser();
        //脱敏
        dbUser.setPassword(null);

        //给用户每日登录奖励
        giveUserDailyLoginReward(dbUser);

        //检查安全并且设置记录用户登录信息
        checkSecurityAndRecordUserLoginInfo(dbUser.getId(), userDTO);

        HashMap<String, Object> map = new HashMap<>();
        map.put("id", dbUser.getId());
        String token = JWTUtil.createToken(map, SecurityConfig.JWT_SECRET_KEY.getBytes(StandardCharsets.UTF_8));
        String redisLoginUserKey = RedisUtils.getLoginKey(dbUser.getId());
        //如果重复登录,则覆盖旧的记录,刷新过期时间
        //存放当前登录用户信息到redis-2小时过期
        redisService.setCacheObject(redisLoginUserKey, loginUser, 2L, TimeUnit.HOURS);

        return token;
    }

    @Override
    public void logout() {
        UsernamePasswordAuthenticationToken authentication = (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
        if (authentication == null) {
            return;
        }
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        Long userId = loginUser.getUser().getId();
        String loginKey = RedisUtils.getLoginKey(userId);
        //删除redis中用户登录信息
        redisService.deleteObject(loginKey);
    }

    @Override
    @Transactional
    public void register(UserDTO userDTO) {
        String email = userDTO.getUser().getEmail();
        String emailCodeKey = RedisUtils.getUserRegisterEmailCodeKey(email);
        if (!redisService.hasKey(emailCodeKey)) {
            throw new VerificationCodeException("邮箱验证码已过期");
        }
        String redisEmailCode = redisService.getCacheObject(emailCodeKey);
        if (!StringUtils.hasText(redisEmailCode) || !redisEmailCode.equals(userDTO.getEmailCode())) {
            throw new VerificationCodeException("邮箱验证码错误");
        }
        if (this.queryEmailExist(email)) {
            throw new UserExistException("该邮箱已经注册");
        }
        User user = userDTO.getUser();
        String encryption = SpringSecurityUtils.encryption(user.getPassword());
        user.setPassword(encryption);
        //初始用户基础数据
        initUserBasisData(user);
        //todo 给用户添加对应角色
        if (!this.save(user)) {
            throw new InsertDataBaseException("插入用户数据失败");
        }
        Long userId = user.getId();
        //给用户添加默认分组
        userCollectGroupService.saveUserDefaultGroup(userId);
        //初始化用户默认配置
        userConfigurationService.saveUserDefaultConfiguration(userId);
    }

    @Override
    public void createLoginCode(String email) {
        CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(200, 100, 4, 20);
        String code = captcha.getCode();
        String codeKey = RedisUtils.getUserLoginCodeKey(email);
        //验证码默认设置5分钟过期
        redisService.setCacheObject(codeKey, code, 5L, TimeUnit.MINUTES);
        try (ServletOutputStream outputStream = WebUtils.getResponse().getOutputStream()) {
            captcha.write(outputStream);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void createRegisterCode(String email) {
        CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(200, 100, 4, 20);
        String code = captcha.getCode();
        String codeKey = RedisUtils.getUserRegisterCodeKey(email);
        //验证码默认设置10分钟过期
        redisService.setCacheObject(codeKey, code, 10L, TimeUnit.MINUTES);
        try (ServletOutputStream outputStream = WebUtils.getResponse().getOutputStream()) {
            captcha.write(outputStream);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void createLoginEmailCode(String email) {
        String userLoginEmailCodeKey = RedisUtils.getUserLoginEmailCodeKey(email);
        if (redisService.hasKey(userLoginEmailCodeKey)) {
            throw new VerificationCodeException("邮箱验证码还在有效期内,请登录邮箱查看");
        }
        String loginCode = RandomUtil.randomString(6).toUpperCase();
        EmailUtils.sendLoginCode(email, loginCode);
        redisService.setCacheObject(userLoginEmailCodeKey, loginCode, 5L, TimeUnit.MINUTES);
    }

    @Override
    public void createFindPasswordCode(String email) {
        CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(200, 100, 4, 20);
        String code = captcha.getCode();
        String codeKey = RedisUtils.getFindPasswordCodeKey(email);
        //验证码默认设置5分钟过期
        redisService.setCacheObject(codeKey, code, 5L, TimeUnit.MINUTES);
        try (ServletOutputStream outputStream = WebUtils.getResponse().getOutputStream()) {
            captcha.write(outputStream);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void createFindPasswordEmailCode(String email, String code) {
        String codeKey = RedisUtils.getFindPasswordCodeKey(email);
        if (!redisService.hasKey(codeKey)) {
            throw new VerificationCodeException("图形验证码已过期,请重新输入");
        }
        String redisCode = redisService.getCacheObject(codeKey);
        if (!StringUtils.hasText(redisCode) || !redisCode.equals(code)) {
            //用户输入错误验证码后删除旧的验证码
            redisService.deleteObject(codeKey);
            throw new VerificationCodeException("图形验证码错误");
        }
        if (!this.queryEmailExist(email)) {
            throw new UserExistException("该邮箱未注册");
        }
        String emailCodeKey = RedisUtils.getFindPasswordEmailCodeKey(email);
        if (redisService.hasKey(emailCodeKey)) {
            throw new VerificationCodeException("邮箱验证码还在有效期内,请登录邮箱查看");
        }
        String findPasswordCode = RandomUtil.randomString(6).toUpperCase();
        EmailUtils.sendFindPasswordCode(email, findPasswordCode);
        redisService.setCacheObject(emailCodeKey, findPasswordCode, 5L, TimeUnit.MINUTES);
    }

    @Override
    public void createRegisterEmailCode(String email, String code) {
        String codeKey = RedisUtils.getUserRegisterCodeKey(email);
        if (!redisService.hasKey(codeKey)) {
            throw new VerificationCodeException("图形验证码已过期,请重新输入");
        }
        String redisCode = redisService.getCacheObject(codeKey);
        if (!StringUtils.hasText(redisCode) || !redisCode.equals(code)) {
            //用户输入错误验证码后删除旧的验证码
            redisService.deleteObject(codeKey);
            throw new VerificationCodeException("图形验证码错误");
        }
        if (this.queryEmailExist(email)) {
            throw new UserExistException("该邮箱已经注册");
        }
        String emailCodeKey = RedisUtils.getUserRegisterEmailCodeKey(email);
        if (redisService.hasKey(emailCodeKey)) {
            throw new VerificationCodeException("邮箱验证码还在有效期内,请登录邮箱查看");
        }
        String registerCode = RandomUtil.randomString(6).toUpperCase();
        EmailUtils.sendRegisterCode(email, registerCode);
        redisService.setCacheObject(emailCodeKey, registerCode, 5L, TimeUnit.MINUTES);
    }


    @Override
    public boolean queryEmailExist(String email) {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("email", email);
        return this.count(wrapper) == 1;
    }

    @Override
    public UserVO queryUserInfo() {
        LoginUser loginUser = SpringSecurityUtils.getCurrentLoginUserInfo();
        User user = loginUser.getUser();
        Long userId = user.getId();
        UserVO userVO = userMapper.queryUserInfo(userId);
        userVO.setUser(user);
        userVO.setUserLevel(UserUtils.getUserLevel(user.getExp()));
        return userVO;
    }

    @Override
    public void resetPassword(UserDTO userDTO) {
        User user = userDTO.getUser();
        String email = user.getEmail();
        String password = user.getPassword();
        String emailCode = userDTO.getEmailCode();

        //根据邮箱找回密码
        if (StringUtils.hasText(emailCode)) {
            String findPasswordEmailCodeKey = RedisUtils.getFindPasswordEmailCodeKey(email);
            if (!redisService.hasKey(findPasswordEmailCodeKey)) {
                throw new VerificationCodeException("邮箱验证码已过期,请重新输入");
            }
            String redisEmailCode = redisService.getCacheObject(findPasswordEmailCodeKey);
            if (!emailCode.equals(redisEmailCode)) {
                throw new VerificationCodeException("邮箱验证码错误");
            }
            String encryption = SpringSecurityUtils.encryption(password);
            if (!this.updatePasswordByEmail(email, encryption)) {
                throw new UpdateDataBaseException("重置密码失败");
            }
            //成功后删除验证码
            redisService.deleteObject(findPasswordEmailCodeKey);
            return;
        }
        //在设置里面修改密码
        if (StringUtils.hasText(userDTO.getOldPassword())) {
            LoginUser loginUser = SpringSecurityUtils.getCurrentLoginUserInfo();
            email = loginUser.getUser().getEmail();
            Long userId = loginUser.getUser().getId();
            UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(email, userDTO.getOldPassword());
            try {
                authenticationManager.authenticate(token);
            } catch (AuthenticationException e) {
                throw new UserAuthenticationException("旧密码不正确");
            }

            User updateUser = new User();
            updateUser.setPassword(SpringSecurityUtils.encryption(user.getPassword()));
            updateUser.setId(userId);
            if (!this.updateById(updateUser)) {
                throw new UpdateDataBaseException("修改用户密码失败");
            }
            String loginKey = RedisUtils.getLoginKey(userId);
            redisService.deleteObject(loginKey);
        }

    }

    @Override
    public boolean updatePasswordByEmail(String email, String newPassword) {
        User user = new User();
        user.setPassword(newPassword);
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("email", email);
        return this.update(user, wrapper);
    }

    @Override
    public PublishUserVO queryPublishUserInfo(Long publishUserId) {
        Long userId = SpringSecurityUtils.getCurrentLoginUserId();
        PublishUserVO publishUserVO = userMapper.queryPublishUserInfo(publishUserId, userId);
        if (Objects.isNull(publishUserVO)) {
            throw new DataNotExistException("查询文章发布者信息为空");
        }
        int userLevel = UserUtils.getUserLevel(publishUserVO.getPublishUserExp());
        publishUserVO.setPublishUserLevel(userLevel);
        return publishUserVO;
    }

    @Override
    public User queryUserById(Long userId) {
        User user = this.getById(userId);
        if (Objects.isNull(user)) {
            throw new DataNotExistException("没有对应用户数据");
        }
        return user;
    }

    @Override
    public User queryUserRiceGrainNumber(Long userId) {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("id", userId)
                .select("id", "rice_grain_number");
        User user = this.getOne(wrapper);
        if (Objects.isNull(user)) {
            throw new DataNotExistException("没有对应用户数据");
        }
        return user;
    }

    @Override
    public boolean updateUserRiceGrainNumberById(User user, Double oldRiceGrainNumber) {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("id", user.getId())
                .eq("rice_grain_number", oldRiceGrainNumber);
        return this.update(user, wrapper);
    }

    @Override
    public List<User> fuzzyQueryByUserNickNameLimit8(String nickName) {
        Long userId = SpringSecurityUtils.getCurrentLoginUserId();
        if (!StringUtils.hasText(nickName)) {
            return null;
        }
        nickName = SqlUtils.splitJointPercentSignAroundValue(nickName);
        return userMapper.fuzzyQueryByUserNickNameLimit8(nickName, userId);
    }

    @Override
    public boolean updateUserData(User user) {
        Long userId = SpringSecurityUtils.getCurrentLoginUserId();
        user.setId(userId);
        boolean update = this.updateById(user);
        //更新成功后修改redis中的内容
        if (update) {
            String loginKey = RedisUtils.getLoginKey(userId);
            LoginUser loginUser = redisService.getCacheObject(loginKey);
            User dbUser = this.getById(userId);
            loginUser.setUser(dbUser);
            long expire = redisService.getExpire(loginKey);
            redisService.setCacheObject(loginKey, loginUser, expire, TimeUnit.SECONDS);
        }
        return update;
    }

    @Override
    public boolean updateUserAvatar(String newAvatarName) {
        User user = new User();
        user.setAvatarResourceName(newAvatarName);
        return this.updateUserData(user);
    }

    @Override
    public PageResult<User> searchUserByNickName(String keyword, Long pageNumber, Long pageSize) {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.like("nick_name", keyword);
        Page<User> page = new Page<>(pageNumber, pageSize);
        return SqlUtils.fillPageResult(this.page(page, wrapper));
    }


    /**
     * 给用户每日登录奖励5个米粒
     *
     * @param user 用户
     */
    private void giveUserDailyLoginReward(User user) {
        Long userId = user.getId();
        if (userLoginLogService.queryUserToDayLogin(userId)) {
            return;
        }
        Double oldUserRiceGrainNumber = user.getRiceGrainNumber();
        user.setRiceGrainNumber(oldUserRiceGrainNumber + 5);
        if (!this.updateUserRiceGrainNumberById(user, oldUserRiceGrainNumber)) {
            throw new UpdateDataBaseException("更新用户登录奖励失败");
        }
        userRiceGrainsLogService.saveIncreaseRiceGrainsLog(userId, 5D, "每日登录奖励");
    }


    /**
     * 初始化用户基础数据
     *
     * @param user User对象
     */
    private void initUserBasisData(User user) {
        //设置经验值为0
        user.setExp(0);
        //设置米粒数为0
        user.setRiceGrainNumber(0D);
        //给用户随机设置一个名字
        user.setNickName("小米粒" + RandomUtil.randomNumbers(4));
    }


    /**
     * 检查安全设置并且记录用户登录信息
     *
     * @param userId
     * @param userDTO
     */
    private void checkSecurityAndRecordUserLoginInfo(Long userId, UserDTO userDTO) {
        String email = userDTO.getUser().getEmail();
        HttpServletRequest request = WebUtils.getRequest();
        String ip = IpUtils.getIpAddr(request);
        UserAgent userAgent = WebUtils.getRequestUserAgent(request);
        UserLoginLog loginLog = new UserLoginLog();
        loginLog.setUserId(userId);
        loginLog.setLoginIp(ip);
        //如果能获取到操作系统和浏览器则记录
        if (!Objects.isNull(userAgent)) {
            loginLog.setOperatingSystem(userAgent.getPlatform().getName());
            loginLog.setBrowserName(userAgent.getBrowser().getName());
        }
        //ip对应的地址
        String ipAddress = null;
        //查询用户使用使用过这个ip登录过
        boolean loggedInFromIp = userLoginLogService.queryUserLoggedInFromIp(userId, ip);
        if (loggedInFromIp) {
            //如果登录过,ip的信息就不再去调用淘宝的接口查询了,防止次数太多给禁用了
            ipAddress = userLoginLogService.queryLastTimeLoginIpAddress(userId, ip);
        } else {
            JSONObject info = IpUtils.queryIpInfoByIp(ip);
            if (!Objects.isNull(info)) {
                JSONObject data = info.getJSONObject("data");
                //城市名
                String city = data.getString("city");
                //国家名
                String country = data.getString("country");
                ipAddress = country + "-" + city;
            }
            //如果没有   1.获取ip对应的地址 2.根据用户设置执行对应安全策略
            UserConfiguration userConfiguration = userConfigurationService.queryUserConfigurationByUserId(userId);
            if (Objects.isNull(userConfiguration) || Objects.isNull(userConfiguration.getNewIpLoginOperation())) {
                throw new IllegalArgumentException("用户配置为空");
            }
            switch (userConfiguration.getNewIpLoginOperation()) {
                case UserConfigurationConstant.NEW_IP_LOGIN_NOTING:
                    //do noting
                    break;
                case UserConfigurationConstant.NEW_IP_LOGIN_SEND_EMAIL:
                    //发邮件提示
                    String finalIpAddress = ipAddress;
                    if (!Objects.isNull(userAgent)) {
                        ThreadPoolUtil.execute(() -> {
                            EmailUtils.sendNewAddressLoginTipMessage(email, ip,
                                    userAgent.getPlatform().getName(),
                                    userAgent.getBrowser().getName(),
                                    finalIpAddress);
                        });

                    } else {
                        ThreadPoolUtil.execute(() -> {
                            EmailUtils.sendNewAddressLoginTipMessage(email, ip,
                                    null,
                                    null,
                                    finalIpAddress);
                        });
                    }
                    break;
                case UserConfigurationConstant.NEW_IP_LOGIN_EMAIL_VERIFY:
                    //检查验证码
                    String emailCode = userDTO.getEmailCode();
                    if (!StringUtils.hasText(emailCode)) {
                        throw new NewIpLoginException("邮箱验证码不能为空");
                    }
                    String userLoginEmailCodeKey = RedisUtils.getUserLoginEmailCodeKey(email);
                    if (!redisService.hasKey(userLoginEmailCodeKey)) {
                        throw new VerificationCodeException("验证码已过期,请重新生成");
                    }
                    String redisEmailCode = redisService.getCacheObject(userLoginEmailCodeKey);
                    if (!emailCode.equals(redisEmailCode)) {
                        throw new VerificationCodeException("输入的验证码不正确,请检查后重试");
                    }
                    break;
            }
        }
        if (StringUtils.hasText(ipAddress)) {
            loginLog.setAddress(ipAddress);
        }
        if (!userLoginLogService.save(loginLog)) {
            throw new InsertDataBaseException("保存登录日志失败");
        }
    }

    /**
     * 登录认证失败处理
     * <p>同一账号5分钟内连续3次输错密码后</p>
     * 或者
     * <p>同一ip 5分钟内连续3次输错密码后</p>
     * 下次登录请求需要携带验证码
     *
     * @param userDTO 登录对象
     */
    private void loginAuthenticationFailHandler(UserDTO userDTO) {
        HttpServletRequest request = WebUtils.getRequest();
        //获取请求ip
        String ip = IpUtils.getIpAddr(request);
        //获取用户邮箱
        String email = userDTO.getUser().getEmail();
        //获取用户输入的验证码,可能为空
        String code = userDTO.getCode();

        String ipKey = RedisUtils.getUserLoginFailIpKey(ip);
        String emailKey = RedisUtils.getUserLoginFailEmailKey(email);
        int ipFailNumber = loginRequestLimit(ipKey, code, email);
        int emailFailNumber = loginRequestLimit(emailKey, code, email);
        int failNumber = Math.max(ipFailNumber, emailFailNumber);
        //将失败次数返回前端,超过3次提示让用户输入验证码
        throw new UserAuthenticationException("用户名或密码错误", failNumber);
    }

    /**
     * 登录操作请求限流
     * 5分钟3次登录
     *
     * @param key   限流key
     * @param code  用户输入的验证码
     * @param email 用户登录邮箱
     * @return 登录操作失败次数
     */
    public int loginRequestLimit(String key, String code, String email) {
        boolean limitKeyExist = false;
        //失败次数
        Integer failNumber = 1;
        if (redisService.hasKey(key)) {
            failNumber = redisService.getCacheObject(key);
            if (!Objects.isNull(failNumber)) {
                //没有超出失败上限的情况,查询上次剩余时间
                long expire = redisService.getExpire(key);
                if (expire > 0) {
                    //如果没过期则将失败次数++
                    redisService.setCacheObject(key, ++failNumber, expire, TimeUnit.SECONDS);
                }
                limitKeyExist = true;

                //当失败次数大于3次后,下次提交需要填写验证码
                if (failNumber > 3) {
                    if (!StringUtils.hasText(code)) {
                        throw new UserAuthenticationException("验证码为空!", failNumber);
                    }
                    String userLoginCodeKey = RedisUtils.getUserLoginCodeKey(email);
                    String loginCode = redisService.getCacheObject(userLoginCodeKey);

                    //当验证码输入错误后重新生成新的验证码
                    if (!code.equals(loginCode)) {
                        //删除旧验证码
                        redisService.deleteObject(userLoginCodeKey);
                        throw new UserAuthenticationException("验证码不正确!", failNumber);
                    }
                }
            }
        }
        if (!limitKeyExist) {
            redisService.setCacheObject(key, failNumber, 5L, TimeUnit.MINUTES);
        }
        return failNumber;
    }
    /*
    每天
        登录 加5
        看前文章十个每个加1
        首次评论加5

     */


}
